/*******************************************************************************
 * Software Name : Android Simple Downloader
 *
 * Copyright © 2012 Rinvay Tang
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package com.rinvay.filedownload;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.MalformedURLException;
import java.nio.channels.FileLock;

import com.rinvay.filedownload.model.DownloadTask;
import com.rinvay.filedownload.model.Part;
import com.rinvay.network.http.HttpRequest;
import com.rinvay.network.http.conn.HttpConnection;
import com.rinvay.network.http.exception.NetWorkInvalidException;
import com.rinvay.utils.logger.Logger;

/**
 * 文件下载连接，和一般连接略有差别，直接将返回流的数据写入文件
 * 
 * @author tyf
 * @date 2012-3-12
 * @time 下午3:28:53
 */
public class FileDownloadHttpConnection extends HttpConnection
{

    private static final String TAG = "FileDownloadHttpConnection";

    private Part part;

    private int downloadSize = 0;

    protected FileDownloadHttpConnection(Part part) {
        this(part, null);
    }

    protected FileDownloadHttpConnection(Part part,
            FileDownloadHttpConnectionListener listener) {
        this.part = part;
        this.listener = listener;

        request = new HttpRequest(part.getResource().getResourceUrl());
        request.setHeaders(part.getResource().getConnProperties());
        if (part.getSize() == -1) {
            request.setHeader("Range",
                    "bytes=" + (part.getBegin() + part.getCurLength()));
        } else {
            request.setHeader("Range",
                    "bytes=" + (part.getBegin() + part.getCurLength()) + "-"
                            + (part.getBegin() + part.getSize() - 1));
        }
        Logger.info(TAG, request.getHeader("Range"));
    }

    @Override
    public void run() {
        RandomAccessFile rav = null;
        boolean hasException = false;
        try {
            Logger.info(TAG, getName() + "  start");
            httpConnectionState = CONNECTION_STATE_CONNECTING;
            if (listener != null) {
                listener.onConnecting();
            }

            connect();

            httpConnectionState = CONNECTION_STATE_CONNECTED;
            if (listener != null) {
                listener.onConnected();
            }
//            rav = new RandomAccessFile(part.getResource().getFileDirectory()
//                    + File.separator + part.getResource().getFileName(), "rw");
            File file = new File(part.getResource().getFileDirectory(), part
                    .getResource().getFileName());
            rav = new RandomAccessFile(file, "rws");
            save2File(getInputStream(), rav);
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            hasException = true;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            hasException = true;
        } catch (NetWorkInvalidException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            hasException = true;
        } finally {
            Logger.info(TAG, getName() + "end data downloaded " + downloadSize);
            Logger.info(
                    TAG,
                    getName() + " " + part.getCurLength() + "/"
                            + part.getSize());
            if (rav != null) {
                try {
                    rav.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            close();

            if (part.isPartFinished()) {
                Logger.info(TAG, getName() + " part finished");
                part.setState(DownloadTask.STATE_FINISHED);
                if (listener != null) {
                    ((FileDownloadHttpConnectionListener) listener)
                            .onTransferred(part.getResource().getUUId());
                }
            } else if (part.getResource().getState() == DownloadTask.STATE_PAUSED) {
                Logger.info(TAG, getName() + " part paused");
                part.setState(DownloadTask.STATE_PAUSED);
            } else {
                Logger.info(TAG, getName() + " part failed");
                part.setState(DownloadTask.STATE_FAILED);
                if (listener != null) {
                    ((FileDownloadHttpConnectionListener) listener)
                            .onTransError(part.getResource().getUUId());
                }
            }

//            part.setState(DownloadTask.STATE_FINISHED);
//            if (hasException && !part.isPartFinished()) {
//                part.setState(DownloadTask.STATE_FAILED);
//                if (listener != null) {
//                    ((FileDownloadHttpConnectionListener) listener)
//                            .onTransError(part.getResource().getUUId());
//                }
//            } else {
//                if (listener != null) {
//                    if (part.getResource().updateTaskFinished()) {
//                        ((FileDownloadHttpConnectionListener) listener)
//                                .onTransferred(part.getResource().getUUId());
//                    } else {
//                        ((FileDownloadHttpConnectionListener) listener)
//                                .onTransProgress(part.getResource().getUUId());
//                    }
//                }
//            }
        }

    }

    private void save2File(InputStream input, RandomAccessFile rav)
            throws IOException {

        downloadSize = 0;
        Logger.info(TAG, getName() + "start save2File downloaded:"
                + downloadSize);
        byte[] buffer = new byte[MAX_BUFFER_SIZE];
        int perRead = 0;
        part.setState(DownloadTask.STATE_DOWNLOADING);

        /*FileLock lock = rav.getChannel().lock(part.getBegin(), part.getSize(), false); */

        rav.seek(part.getBegin() + part.getCurLength());

        while ((part.getResource().getState() != DownloadTask.STATE_PAUSED)
                && (perRead = input.read(buffer)) != -1) {
            // 判断资源对象的状态是否被修改成暂停

            synchronized (rav) {
                rav.write(buffer, 0, perRead);
                downloadSize += perRead;
            }
            part.setCurLength(part.getCurLength() + perRead);

            if (listener != null) {
                ((FileDownloadHttpConnectionListener) listener)
                        .onTransProgress(part.getResource().getUUId());
            }

            Logger.debug(TAG, getName() + " save2File write:" + downloadSize);
            Logger.debug(TAG,
                    getName() + "  " + (part.getBegin() + part.getCurLength())
                            + "/" + (part.getBegin() + part.getSize()));
        }

        if (part.getResource().getState() == DownloadTask.STATE_PAUSED) {
            Logger.info(TAG, getName() + " paused");
        }
    }

    public final static int MAX_BUFFER_SIZE = 2 * 1024;
}
